#pragma once
#include <iostream>
#include <string>
#include <vector>
#include<sstream>
#include<fstream>
#include<unordered_map>
#include"log.hpp"

const std::string token = "\r\n";//请求行和响应行的分隔符
const std::string line_token = " ";//请求行和状态行的行内分割符
const std::string header_token = ": ";//请求报头一行内的分隔符
const std::string blankline = token;//空行
const std::string homepage = "wwwroot/";//网站根目录
const std::string page404 = "wwwroot/404.html";//404页面
const std::string firstpage = "index.html";//网站首页
const std::string http_version = "HTTP/1.0";//HTTP协议版本
// GET / HTTP/1.1\r\n
// Host: 121.37.136.212:8080
// Connection: keep-alive
// Upgrade-Insecure-Requests: 1
// User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0
// Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
// Accept-Encoding: gzip, deflate
// Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
//
bool Parse2OneLine(std::string &in,std::string *out,const std::string &tok)//将数据按照行分割符分成一行数据
{
    int n = in.find(tok);
    if(n == std::string::npos) return false;
    *out = in.substr(0,n);
    in.erase(0,n+tok.size());
    return true;
}
bool SplitString(std::string &line,const std::string &tok,std::string *key,std::string *value)
{
    int pos = line.find(tok);
    if(pos == std::string::npos) return false;
    *key = line.substr(0,pos);
    *value = line.substr(pos+tok.size());
    return true;
}


class HttpRequest{
    public:
        HttpRequest()
        {}
        ~HttpRequest()
        {}
        std::string Path()
        {
            return _path;
        }
        std::string Args()
        {
            return _args;
        }
        bool HasArgs()//判断是否有请求参数
        {
            return _isexec;
        }
        void Deserialize(std::string &req_str)//反序列化，字符串处理
        {
            if(Parse2OneLine(req_str,&_req_line,token)){//处理得到请求行
                ParseRequestLine(_req_line);//解析请求行
                ParseRequestHeader(req_str);//解析请求报头
                _body = req_str;//请求报文主体
            }
            //分析请求中是否有参数
            if(_method == "POST"){//如果是POST请求，参数在正文部分需要分析请求参数(且body不能为空)
                _isexec = true;
                _args = _body;
                _path = _uri;
            }else if(_method == "GET"){
                auto pos = _uri.find('?');
                if(pos != std::string::npos){
                    _isexec = true;
                    _path = _uri.substr(0,pos);//请求路径
                    _args = _uri.substr(pos+1);//请求参数
                }
            }
        }
        std::string Suffix()//获取请求资源的后缀名
        {
            auto pos = _uri.rfind('.');
            if(pos == std::string::npos) return std::string(".html");
            return _uri.substr(pos);
        }
        std::string GetContent(const std::string path)//获取请求在wwwroot目录下的资源
        {
            std::string content;
            std::ifstream in(path,std::ios::binary);//打开文件(二进制)
            if(!in.is_open()) return std::string();
            in.seekg(0,in.end);//定位到文件末尾
            int file_size = in.tellg();
            in.seekg(0,in.beg);//定位到文件开头
            content.resize(file_size);
            in.read((char*)content.c_str(),file_size);//读取文件内容(不规范，这里只是为了测试)
            in.close();
            return content;
            // 暂时做法只能读文本
            // std::string content;
            // std::ifstream in(_uri);
            // if (!in.is_open())
            //     return std::string();
            // std::string line;
            // while (std::getline(in, line))
            // {
            //     content += line;
            // }
            // in.close();
            // return content;
        }
        std::string Uri()
        {
            return _uri;
        }
        void SetUri(std::string uri)
        {
            _uri = uri;
        }
        void Print()
        {
            std::cout << "_method: " << _method << std::endl;
            std::cout << "_uri: " << _uri << std::endl;
            std::cout << "_version: " << _version << std::endl;
            for(auto &kv : _header_kv){
                std::cout << kv.first << "##" << kv.second << std::endl;
            }
            std::cout << "_blank_line: " << _blank_line << std::endl;
            std::cout << "_body: " << _body << std::endl;
        }
    private:
        void ParseRequestLine(std::string &req_line)//解析请求行填充三个成员变量
        {
            std::stringstream ss(req_line);
            ss >> _method >> _uri >> _version;//req_line中每个单词都有空格分割，所以这里用stringstream来解析
            // _uri = homepage + _uri;
        }
        void ParseHeaderKV()
        {
            std::string key,value;
            for(auto &line : _req_header){
                SplitString(line,header_token,&key,&value);
                _header_kv[key] = value;
            }
        }
        void ParseRequestHeader(std::string &req_str)//解析请求报头
        {
            std::string line;
            while(true){
                bool ret = Parse2OneLine(req_str,&line,token);//处理得到一行数据
                if(ret && !line.empty()){
                    _req_header.push_back(line);
                }else if(ret && line.empty()){
                    _blank_line = token;
                    break;
                }else{
                    return;
                }
            }
            ParseHeaderKV();//解析请求报头的键值对
            return;
        }
    private:
        std::string _req_line;//请求行
        std::vector<std::string> _req_header;//请求报文
        std::string _blank_line;//空行
        // std::vector<char> _body;//请求报文主体
        std::string _body;

        //反序列化过程中，解析出来的字段
        std::string _method;//请求方法
        std::string _uri;//请求路径
        std::string _version;//请求协议版本
        std::unordered_map<std::string,std::string> _header_kv;//请求报头的键值对
        bool _isexec = false;//是否执行过cgi



        std::string _path;
        std::string _args;
};


class HttpResponse{
    public:
        HttpResponse():_version(http_version),_blank_line(token)
        {}
        ~HttpResponse()
        {}
        void BuildResponse(HttpRequest &req)
        {
        // #define TestRedir 1
        
        // #ifdef TestRedir
        //     _status_code = 302;
        //     _status_desc = Suffix2Desc(req.Suffix());
        //     SetHeader("Location",homepage + firstpage);//重定向到首页
        //     for(auto &kv : _header_kv){
        //         _resp_header.push_back(kv.first + header_token + kv.second + token);//填充响应报头
        //     }
        // #else
            std::string uri = homepage + req.Uri();
            if(uri.back() == '/'){
                uri += firstpage;
                // req.SetUri(uri);
            }
            _body = req.GetContent(uri);//寻找请求资源
            if(_body.empty()){//如果请求资源不存在，返回404
                _status_code = 404;
                req.SetUri(page404);
                _body = req.GetContent(uri);//重新获取请求资源
            }else{
                _status_code = 200;
            }
            _status_desc = StatusCode2Desc(_status_code);//根据状态码获取状态描述
            
            if(!_body.empty()){
                SetHeader("Content-Length",std::to_string(_body.size()));//设置Content-Length报头
            }
            std::string mime_type = Suffix2Desc(req.Suffix());//根据请求资源后缀名获取Content-Type报头
            SetHeader("Content-Type",mime_type);

            
        // #endif

        }
        void SetCode(int code)
        {
            _status_code = code;
            _status_desc = StatusCode2Desc(code);
        }
        void SetBody(const std::string &body)
        {
            _body = body;
        }
        void SetHeader(const std::string &key,const std::string &value)
        {
            _header_kv[key] = value;
        }
        void Serialize(std::string *resp_str)
        {
            for(auto &kv : _header_kv){
                _resp_header.push_back(kv.first + header_token + kv.second + token);//将响应报头的键值对组合成一行
            }
            _resp_line = _version +line_token + std::to_string(_status_code) + line_token + _status_desc + token;//填充状态行
            *resp_str = _resp_line;//状态行
            for(auto &line:_resp_header){//填充响应报头
                *resp_str += line;
            }
            *resp_str += _blank_line;//空行
            *resp_str += _body;//响应报文主体
        }
    private:
        std::string StatusCode2Desc(int code)
        {
            switch(code)
            {
                case 200:
                    return "OK";
                case 301:
                    return "Moved Permanently";
                case 302:
                    return "Found";
                case 404:
                    return "Not Found";
                default:
                    return std::string();
            }
        }
        std::string Suffix2Desc(const std::string &suffix)
        {
            if(suffix == ".html") 
                return "text/html";
            else if(suffix == ".jpg")
                return "application/x-jpg";
            else
                return "text/html";
        }

    private:
        //状态行属性
        std::string _version;
        int _status_code;
        std::string _status_desc;
        //响应报头属性
        std::unordered_map<std::string,std::string> _header_kv;

        //响应报文属性用于序列化
        std::string _resp_line;
        std::vector<std::string> _resp_header;
        std::string _blank_line;
        // std::vector<char> _body;
        std::string _body;
};